/*****************************************************************************
 *
 * Weber State University
 * CS4280 Spring 2010
 * Group Assignment 5
 *
 *
 *   TTTTTT                               CCCCC
 *     TT   EEEEE   A    M   M          CC      C
 *     TT   E      A A   M   M         CC   
 *     TT   E     A   A  MM MM  -----  CC
 *     TT   EEE   AAAAA  M M M  -----  CC
 *     TT   E     A   A  M   M          CC      C
 *     TT   EEEEE A   A  M   M            CCCCC
 *
 *   Jared Pack ---- Jon Mann ---- Joshua Clayton
 *
 *
 * A flythrough of a simple textured 3D scene
 *
 ****************************************************************************/

 /* FILENAME flythrough.c
  *
  * Change control Section
  *
  * Team Member: Joshua Clayton
  * Version: 0.1
  * Date: 03/19/2010
  *     Stole some code from nehe.gamedev.net that draws a spinning textured cube.
  *     Split the code into four files:
  *         ImageLoad.h
  *        a header file for ImageLoad.c
  *         ImageLoad.c
  *        which loads a bmp image and will likely be unchanged by us,
  *         scene.c
  *        which contains the srawing and texturing code, and
  *         flythrough.c
  *        which contains the main function, controls, reshape code etc
  *
  *     Brought in three textured files which I designed some time ago,
  *         alienskin.bmp, Blumarble.bmp, maze45smallblue.bmp
  *
  *     Turned the cube inside out (so you are inside it). 
  *     Switched the code to use my textures.
  *
  * Team Member: Jon Mann
  * Version: 0.2
  * Date: 03/23/2010
  *     Dropped in classes from individual assignment for camera control
  *    	Added keyboard controls
  *    	Added mouse controls (for less tedious rotation)
  *
  *
  */
#ifdef _WIN32
#include<windows.h> // needed for windows systems
#endif

#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream>

#include "ImageLoad.h"
#include "Camera.h"
#include "Vector3.h"

using namespace std;

/* ascii code for the escape key */
#define ESCAPE 27

Camera cam;

/* The number of our GLUT window */
int window; 

/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
Vector3 rot_axis;
int mousePosX = 0;
int mousePosY = 0;
extern GLuint texture[3];

extern void DrawGLScene(void);
extern void rotateCube(void);
extern int LoadGLTexture(char * filename, GLuint *texture);

/* A general OpenGL initialization function.  Sets all of the initial parameters. */
void InitGL(int Width, int Height)
{
    LoadGLTexture("Data/alienskin.bmp", &texture[0]);
    LoadGLTexture("Data/Bluemarble.bmp", &texture[1]);
    LoadGLTexture("Data/maze45smallblue.bmp", &texture[2]);

    glEnable(GL_TEXTURE_2D);
    glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
    glClearDepth(1.0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    
    gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
    
    glMatrixMode(GL_MODELVIEW);
}

/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
    /* Prevent A Divide By Zero If The Window Is Too Small */
    if (Height==0)
    Height=1;
    /* Reset The Current Viewport And Perspective Transformation */
    glViewport(0, 0, Width, Height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
    glMatrixMode(GL_MODELVIEW);
}

// this is the mouse event handler
// the x and y parameters are the mouse coordinates when the button was pressed
void mouse(int button, int state, int x, int y)
{
    //cout << x; // for debugging

    switch(button)
    {
    case GLUT_LEFT_BUTTON:
    	if (state == GLUT_DOWN) 
    	{
                rot_axis.set(0, 0, 1);
    		cam.rotate(rot_axis, -1); break;
    	}
    	break;
    case GLUT_RIGHT_BUTTON:
    	if (state == GLUT_DOWN) 
    	{
                rot_axis.set(0, 0, 1);
    		cam.rotate(rot_axis, 1); break;
    	}
    	break;
    default:
    	break;
    }
}

void mouseMove(int x, int y)
{
    mousePosX = x - mousePosX;
    mousePosY = y - mousePosY;

    rot_axis.set(0, 1, 0);
    cam.rotate(rot_axis, mousePosX); 
    rot_axis.set(1, 0, 0);
    cam.rotate(rot_axis, mousePosY); // airplane controls :)

    mousePosX = x;
    mousePosY = y;
}

/* The function called whenever a key is pressed. */
void keyPressed(unsigned char key, int x, int y) 
{
    switch (key)
    {
    	// camera slide controls
    	case 'w':
        cam.slide(0, 0, -0.2);
        break; // slide camera forward
    	case 's':
        cam.slide(0, 0, 0.2);
        break; // slide camera back
    	case 'q':
        cam.slide(0, 0.2, 0);
        break; // slide camera up
    	case 'z':
        cam.slide(0, -0.2, 0);
        break; // slide camera down
    	case 'a':
        cam.slide(-0.2, 0, 0);
        break; // slide camera left
    	case 'd':
        cam.slide(0.2, 0, 0);
        break; // slide camera right

    	// camera pitch controls
    	case 'i':
        rot_axis.set(1, 0, 0);
        cam.rotate(rot_axis, -1);
        break;
    	case 'k':
        rot_axis.set(1, 0, 0);
        cam.rotate(rot_axis, 1);
        break;
    	// camera yaw controls
    	case 'j':
        rot_axis.set(0, 1, 0);
        cam.rotate(rot_axis, -1);
        break;
    	case 'l':
        rot_axis.set(0, 1, 0);
        cam.rotate(rot_axis, 1);
        break;
    	// camera roll controls
    	case ',':
        rot_axis.set(0, 0, 1);
        cam.rotate(rot_axis, 1);
        break;
    	case '.':
        rot_axis.set(0, 0, 1);
        cam.rotate(rot_axis, -1);
        break;

    	case ESCAPE:
        glutDestroyWindow(window); exit(0);
        break; 
    }
    glutPostRedisplay(); // draws it again
}

int main(int argc, char **argv) 
{  
    glutInit(&argc, argv);  

    /* Select type of Display mode:   
     Double buffer 
     RGBA color
     Alpha components supported 
     Depth buffer */  
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);  

    /* get a 640 x 480 window */
    glutInitWindowSize(640, 480);  

    /* the window starts at the upper left corner of the screen */
    glutInitWindowPosition(0, 0);  

    /* Open a window */  
    window = glutCreateWindow("Team C textured scene flythrough");

    /* Register the function to do all our OpenGL drawing. */
    glutDisplayFunc(&DrawGLScene);  

    /* Go fullscreen.  This is as soon as possible. */
    /* glutFullScreen(); */

    /* Register the function called when our window is resized. */
    glutReshapeFunc(&ReSizeGLScene);

    /* Register the function called when the keyboard is pressed. */
    glutKeyboardFunc(&keyPressed);

    glutMouseFunc(mouse);
    glutPassiveMotionFunc(mouseMove); 

    /* Initialize our window. */
    InitGL(640, 480);

    /* glut does this when its not busy with other calculations */
    glutIdleFunc(rotateCube);
  
    /* Start Event Processing Engine */  
    glutMainLoop();  

    return 1;
}
